package com.xc.ezplan.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.ezplan.admin.entity.AdminRole;
import com.xc.ezplan.admin.entity.AdminRolesMenus;
import com.xc.ezplan.admin.entity.AdminUsersRoles;
import com.xc.ezplan.admin.mapper.AdminRolesMenusMapper;
import com.xc.ezplan.admin.mapper.AdminUsersRolesMapper;
import com.xc.ezplan.admin.service.AdminRoleService;
import com.xc.ezplan.admin.mapper.AdminRoleMapper;
import com.xc.ezplan.admin.vo.AdminRoleVo;
import com.xc.ezplan.cache.constants.RedisKey;
import com.xc.ezplan.cache.utils.CacheUtil;
import com.xc.ezplan.core.base.EzResult;
import com.xc.ezplan.core.base.SearchCondition;
import com.xc.ezplan.core.exception.BadRequestException;
import com.xc.ezplan.core.exception.EntityExistException;
import com.xc.ezplan.core.utils.FileUtil;
import com.xc.ezplan.core.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author lixingchen
 * @date 2022/11/19
 * @description 角色管理实现类
 */
@Service
@Primary
@RequiredArgsConstructor
@CacheConfig(cacheNames = "role")
public class AdminRoleServiceImpl extends ServiceImpl<AdminRoleMapper, AdminRole> implements AdminRoleService {

	private final AdminRoleMapper adminRoleMapper;
	private final AdminRolesMenusMapper adminRolesMenusMapper;
	private final AdminUsersRolesMapper adminUsersRolesMapper;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void createRole(AdminRoleVo adminRoleVo) {
		// 校验角色名是否重名
		if (adminRoleMapper.selectOne(
				new QueryWrapper<AdminRole>().lambda().eq(AdminRole::getName, adminRoleVo.getName())) != null) {
			throw new EntityExistException(AdminRole.class, "roleName", adminRoleVo.getName());
		}
		AdminRole adminRole = new AdminRole();
		BeanUtils.copyProperties(adminRoleVo, adminRole);
		adminRoleMapper.insert(adminRole);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteRole(List<Long> roleIds) {
		// 删除角色
		adminRoleMapper.delete(new QueryWrapper<AdminRole>().lambda().in(AdminRole::getId, roleIds));
		// 查用户角色关联关系
		List<Long> userIds = adminUsersRolesMapper
				.selectList(new QueryWrapper<AdminUsersRoles>().lambda().in(AdminUsersRoles::getRoleId, roleIds))
				.stream().map(AdminUsersRoles::getUserId).collect(Collectors.toList());
		// 删除用户角色关联关系
		adminUsersRolesMapper
				.delete(new QueryWrapper<AdminUsersRoles>().lambda().in(AdminUsersRoles::getRoleId, roleIds));
		// 清除用户拥有的权限和角色缓存
		CacheUtil.deleteCache(RedisKey.PURVIEW_PERMISSION_ID, userIds);
		CacheUtil.deleteCache(RedisKey.PURVIEW_ROLE_ID, userIds);
		// 清除角色缓存
		CacheUtil.deleteCache(RedisKey.ROLE_ID, roleIds);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateRole(AdminRoleVo adminRoleVo) {
		// 校验角色id是否存在
		if (Objects.isNull(adminRoleMapper
				.selectOne(new QueryWrapper<AdminRole>().lambda().eq(AdminRole::getId, adminRoleVo.getId())))) {
			throw new BadRequestException("更新时未传入角色的id");
		}
		// 校验角色名是否重名
		if (Objects.nonNull(adminRoleMapper.selectOne(new QueryWrapper<AdminRole>().lambda()
				.eq(AdminRole::getName, adminRoleVo.getName()).ne(AdminRole::getId, adminRoleVo.getId())))) {
			throw new EntityExistException(AdminRole.class, "name", adminRoleVo.getName());
		}
		AdminRole adminRole = new AdminRole();
		BeanUtils.copyProperties(adminRoleVo, adminRole);
		adminRoleMapper.update(adminRole,
				new UpdateWrapper<AdminRole>().lambda().eq(AdminRole::getId, adminRole.getId()));
		CacheUtil.deleteCache(RedisKey.ROLE_ID, adminRoleVo.getId());
	}

	@Override
	@Cacheable(key = "'id:' + #p0")
	public Object findRoleById(Long roleId) {
		AdminRoleVo adminRoleVo = new AdminRoleVo();
		if (roleId != null) {
			AdminRole adminRole = adminRoleMapper
					.selectOne(new QueryWrapper<AdminRole>().lambda().eq(AdminRole::getId, roleId));
			BeanUtils.copyProperties(adminRole, adminRoleVo);
		}
		return adminRoleVo;
	}

	@Override
	public Object pageQueryRole(SearchCondition searchCondition, Page<AdminRole> page) {
		List<Date> createTime = searchCondition.getCreateTime();
		LambdaQueryWrapper<AdminRole> queryWrapper = new QueryWrapper<AdminRole>().lambda().like(
				StringUtils.isNotBlank(searchCondition.getKeyWord()), AdminRole::getName, searchCondition.getKeyWord());
		if (!CollectionUtils.isEmpty(createTime) && createTime.size() == 2) {
			queryWrapper.between(AdminRole::getCreateTime, createTime.get(0), createTime.get(1));
		}
		return adminRoleMapper.selectPage(page, queryWrapper);
	}

	@Override
	public Object queryAllRole() {
		return adminRoleMapper
				.selectList(new QueryWrapper<AdminRole>().lambda().orderBy(true, true, AdminRole::getLevel));
	}

	@Override
	public Object getRoleLevel() {
		return EzResult.ok();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateRoleMenu(AdminRoleVo adminRoleVo) {
		Long roleId = adminRoleVo.getId();
		// 删除角色菜单关联
		adminRolesMenusMapper
				.delete(new QueryWrapper<AdminRolesMenus>().lambda().eq(AdminRolesMenus::getRoleId, roleId));
		// 添加角色菜单关联
		adminRoleVo.getMenus().forEach(menu -> {
			AdminRolesMenus adminRolesMenus = new AdminRolesMenus();
			adminRolesMenus.setRoleId(roleId);
			adminRolesMenus.setMenuId(menu.getId());
			adminRolesMenusMapper.insert(adminRolesMenus);
		});
	}

	@Override
	public void exportRole(List<AdminRoleVo> adminRoleVos, HttpServletResponse response) throws IOException {
		List<Map<String, Object>> list = new ArrayList<>();
		for (AdminRoleVo role : adminRoleVos) {
			Map<String, Object> map = new LinkedHashMap<>();
			map.put("角色名称", role.getName());
			map.put("角色级别", role.getLevel());
			map.put("描述", role.getDescription());
			map.put("创建日期", role.getCreateTime());
			list.add(map);
		}
		FileUtil.downloadExcel(list);
	}

}
